#include "samplingmanager.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QStandardPaths>
#include <QDir>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>

SamplingManager::SamplingManager(QObject *parent)
    : QObject(parent)
    , m_deviceController(nullptr)
    , m_auditLogger(nullptr)
    , m_scheduleTimer(nullptr)
    , m_scheduleStatus(SCHEDULE_IDLE)
    , m_nextTaskId(1)
    , m_currentTaskId(-1)
    , m_completedTasksCount(0)
{
    // Initialize schedule timer
    m_scheduleTimer = new QTimer(this);
    connect(m_scheduleTimer, &QTimer::timeout, this, &SamplingManager::checkScheduledTasks);
    
    // Start checking every 10 seconds
    m_scheduleTimer->start(10000);
}

SamplingManager::~SamplingManager()
{
    // Save tasks before destruction
    saveTasksToDatabase();
}

bool SamplingManager::initialize(DeviceController* deviceController, AuditLogger* auditLogger)
{
    if (!deviceController || !auditLogger) {
        qDebug() << "SamplingManager: Invalid parameters for initialization";
        return false;
    }
    
    m_deviceController = deviceController;
    m_auditLogger = auditLogger;
    
    // Connect device controller signals
    connect(m_deviceController, &DeviceController::samplingCompleted,
            this, &SamplingManager::onDeviceSamplingCompleted);
    connect(m_deviceController, &DeviceController::deviceError,
            this, &SamplingManager::onDeviceError);
    
    // Create database tables
    createTasksTable();
    
    // Load existing tasks
    loadTasksFromDatabase();
    
    qDebug() << "SamplingManager initialized successfully";
    qDebug() << "About to log task operation...";
    logTaskOperation(-1, "INIT", "Sampling manager initialized");
    qDebug() << "Task operation logged successfully";
    
    return true;
}

int SamplingManager::createTimedSamplingTask(const QString& taskName, int samplingTime, 
                                           const QDateTime& scheduledTime, bool isRecurring)
{
    SamplingTask task;
    task.task_id = m_nextTaskId++;
    task.task_name = taskName;
    task.mode = SAMPLING_TIMED;
    task.parameter = samplingTime;
    task.scheduled_time = scheduledTime;
    task.operator_id = "current_user"; // This should be set from user session
    task.is_recurring = isRecurring;
    task.recurrence_interval = isRecurring ? 60 : 0; // Default 1 hour for recurring tasks
    task.is_active = true;
    
    if (!validateTaskParameters(task)) {
        qDebug() << "Invalid task parameters for task:" << taskName;
        return -1;
    }
    
    m_tasks.append(task);
    saveTasksToDatabase();
    
    emit taskCreated(task.task_id, taskName);
    emit pendingTasksChanged(getPendingTasksCount());
    
    QString details = QString("Timed sampling task created - Name: %1, Time: %2s, Scheduled: %3")
                     .arg(taskName).arg(samplingTime).arg(scheduledTime.toString());
    logTaskOperation(task.task_id, "CREATE_TIMED_TASK", details.toLocal8Bit().data());
    
    qDebug() << "Created timed sampling task:" << taskName << "ID:" << task.task_id;
    
    scheduleNextTask();
    return task.task_id;
}

int SamplingManager::createVolumeSamplingTask(const QString& taskName, int samplingVolume, 
                                            const QDateTime& scheduledTime, bool isRecurring)
{
    SamplingTask task;
    task.task_id = m_nextTaskId++;
    task.task_name = taskName;
    task.mode = SAMPLING_VOLUME;
    task.parameter = samplingVolume;
    task.scheduled_time = scheduledTime;
    task.operator_id = "current_user"; // This should be set from user session
    task.is_recurring = isRecurring;
    task.recurrence_interval = isRecurring ? 60 : 0; // Default 1 hour for recurring tasks
    task.is_active = true;
    
    if (!validateTaskParameters(task)) {
        qDebug() << "Invalid task parameters for task:" << taskName;
        return -1;
    }
    
    m_tasks.append(task);
    saveTasksToDatabase();
    
    emit taskCreated(task.task_id, taskName);
    emit pendingTasksChanged(getPendingTasksCount());
    
    QString details = QString("Volume sampling task created - Name: %1, Volume: %2L, Scheduled: %3")
                     .arg(taskName).arg(samplingVolume).arg(scheduledTime.toString());
    logTaskOperation(task.task_id, "CREATE_VOLUME_TASK", details.toLocal8Bit().data());
    
    qDebug() << "Created volume sampling task:" << taskName << "ID:" << task.task_id;
    
    scheduleNextTask();
    return task.task_id;
}

bool SamplingManager::deleteTask(int taskId)
{
    for (int i = 0; i < m_tasks.size(); ++i) {
        if (m_tasks[i].task_id == taskId) {
            QString taskName = m_tasks[i].task_name;
            m_tasks.removeAt(i);
            saveTasksToDatabase();
            
            emit pendingTasksChanged(getPendingTasksCount());
            
            logTaskOperation(taskId, "DELETE_TASK", QString("Task deleted: %1").arg(taskName).toLocal8Bit().data());
            qDebug() << "Deleted task:" << taskName << "ID:" << taskId;
            
            scheduleNextTask();
            return true;
        }
    }
    
    qDebug() << "Task not found for deletion:" << taskId;
    return false;
}

bool SamplingManager::pauseTask(int taskId)
{
    SamplingTask* task = findTask(taskId);
    if (!task) {
        qDebug() << "Task not found for pause:" << taskId;
        return false;
    }
    
    task->is_active = false;
    saveTasksToDatabase();
    
    emit pendingTasksChanged(getPendingTasksCount());
    
    logTaskOperation(taskId, "PAUSE_TASK", QString("Task paused: %1").arg(task->task_name).toLocal8Bit().data());
    qDebug() << "Paused task:" << task->task_name << "ID:" << taskId;
    
    scheduleNextTask();
    return true;
}

bool SamplingManager::resumeTask(int taskId)
{
    SamplingTask* task = findTask(taskId);
    if (!task) {
        qDebug() << "Task not found for resume:" << taskId;
        return false;
    }
    
    task->is_active = true;
    saveTasksToDatabase();
    
    emit pendingTasksChanged(getPendingTasksCount());
    
    logTaskOperation(taskId, "RESUME_TASK", QString("Task resumed: %1").arg(task->task_name).toLocal8Bit().data());
    qDebug() << "Resumed task:" << task->task_name << "ID:" << taskId;
    
    scheduleNextTask();
    return true;
}

bool SamplingManager::executeTaskNow(int taskId)
{
    SamplingTask* task = findTask(taskId);
    if (!task) {
        qDebug() << "Task not found for immediate execution:" << taskId;
        return false;
    }
    
    if (!task->is_active) {
        qDebug() << "Cannot execute inactive task:" << taskId;
        return false;
    }
    
    logTaskOperation(taskId, "EXECUTE_NOW", QString("Task executed immediately: %1").arg(task->task_name).toLocal8Bit().data());
    
    return executeTask(taskId);
}

QList<QVariant> SamplingManager::getAllTasks() const
{
    QList<QVariant> taskList;
    
    for (const auto& task : m_tasks) {
        QVariantMap taskMap;
        taskMap["taskId"] = task.task_id;
        taskMap["taskName"] = task.task_name;
        taskMap["mode"] = static_cast<int>(task.mode);
        taskMap["parameter"] = task.parameter;
        taskMap["scheduledTime"] = task.scheduled_time;
        taskMap["operatorId"] = task.operator_id;
        taskMap["isRecurring"] = task.is_recurring;
        taskMap["recurrenceInterval"] = task.recurrence_interval;
        taskMap["isActive"] = task.is_active;
        
        taskList.append(taskMap);
    }
    
    return taskList;
}

QList<QVariant> SamplingManager::getActiveTasks() const
{
    QList<QVariant> activeTaskList;
    
    for (const auto& task : m_tasks) {
        if (task.is_active) {
            QVariantMap taskMap;
            taskMap["taskId"] = task.task_id;
            taskMap["taskName"] = task.task_name;
            taskMap["mode"] = static_cast<int>(task.mode);
            taskMap["parameter"] = task.parameter;
            taskMap["scheduledTime"] = task.scheduled_time;
            taskMap["operatorId"] = task.operator_id;
            taskMap["isRecurring"] = task.is_recurring;
            taskMap["recurrenceInterval"] = task.recurrence_interval;
            taskMap["isActive"] = task.is_active;
            
            activeTaskList.append(taskMap);
        }
    }
    
    return activeTaskList;
}

QVariant SamplingManager::getTask(int taskId) const
{
    const SamplingTask* task = const_cast<SamplingManager*>(this)->findTask(taskId);
    if (!task) {
        return QVariant();
    }
    
    QVariantMap taskMap;
    taskMap["taskId"] = task->task_id;
    taskMap["taskName"] = task->task_name;
    taskMap["mode"] = static_cast<int>(task->mode);
    taskMap["parameter"] = task->parameter;
    taskMap["scheduledTime"] = task->scheduled_time;
    taskMap["operatorId"] = task->operator_id;
    taskMap["isRecurring"] = task->is_recurring;
    taskMap["recurrenceInterval"] = task->recurrence_interval;
    taskMap["isActive"] = task->is_active;
    
    return taskMap;
}

int SamplingManager::getPendingTasksCount() const
{
    int count = 0;
    QDateTime now = QDateTime::currentDateTime();
    
    for (const auto& task : m_tasks) {
        if (task.is_active && task.scheduled_time > now) {
            count++;
        }
    }
    
    return count;
}

int SamplingManager::getCompletedTasksCount() const
{
    return m_completedTasksCount;
}

ScheduleStatus SamplingManager::getScheduleStatus() const
{
    return m_scheduleStatus;
}

QString SamplingManager::getScheduleStatusString() const
{
    return QString(scheduleStatusToString(m_scheduleStatus));
}

QDateTime SamplingManager::getNextScheduledTime() const
{
    QDateTime nextTime;
    QDateTime now = QDateTime::currentDateTime();
    
    for (const auto& task : m_tasks) {
        if (task.is_active && task.scheduled_time > now) {
            if (!nextTime.isValid() || task.scheduled_time < nextTime) {
                nextTime = task.scheduled_time;
            }
        }
    }
    
    return nextTime;
}

bool SamplingManager::pauseAllTasks()
{
    for (auto& task : m_tasks) {
        task.is_active = false;
    }
    
    saveTasksToDatabase();
    emit pendingTasksChanged(getPendingTasksCount());
    
    logTaskOperation(-1, "PAUSE_ALL", "All tasks paused");
    qDebug() << "All tasks paused";
    
    return true;
}

bool SamplingManager::resumeAllTasks()
{
    for (auto& task : m_tasks) {
        task.is_active = true;
    }
    
    saveTasksToDatabase();
    emit pendingTasksChanged(getPendingTasksCount());
    
    logTaskOperation(-1, "RESUME_ALL", "All tasks resumed");
    qDebug() << "All tasks resumed";
    
    scheduleNextTask();
    return true;
}

bool SamplingManager::clearCompletedTasks()
{
    // Remove expired tasks
    removeExpiredTasks();
    
    m_completedTasksCount = 0;
    emit completedTasksChanged(m_completedTasksCount);
    
    logTaskOperation(-1, "CLEAR_COMPLETED", "Completed tasks cleared");
    qDebug() << "Completed tasks cleared";
    
    return true;
}

bool SamplingManager::exportTasks(const QString& filePath) const
{
    QJsonArray tasksArray;
    
    for (const auto& task : m_tasks) {
        QJsonObject taskObj;
        taskObj["taskId"] = task.task_id;
        taskObj["taskName"] = task.task_name;
        taskObj["mode"] = static_cast<int>(task.mode);
        taskObj["parameter"] = task.parameter;
        taskObj["scheduledTime"] = task.scheduled_time.toString(Qt::ISODate);
        taskObj["operatorId"] = task.operator_id;
        taskObj["isRecurring"] = task.is_recurring;
        taskObj["recurrenceInterval"] = task.recurrence_interval;
        taskObj["isActive"] = task.is_active;
        
        tasksArray.append(taskObj);
    }
    
    QJsonDocument doc(tasksArray);
    
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly)) {
        qDebug() << "Failed to open file for export:" << filePath;
        return false;
    }
    
    file.write(doc.toJson());
    file.close();
    
    qDebug() << "Tasks exported to:" << filePath;
    return true;
}

bool SamplingManager::importTasks(const QString& filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open file for import:" << filePath;
        return false;
    }
    
    QByteArray data = file.readAll();
    file.close();
    
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (!doc.isArray()) {
        qDebug() << "Invalid JSON format in import file";
        return false;
    }
    
    QJsonArray tasksArray = doc.array();
    int importedCount = 0;
    
    for (const auto& value : tasksArray) {
        QJsonObject taskObj = value.toObject();
        
        SamplingTask task;
        task.task_id = m_nextTaskId++;
        task.task_name = taskObj["taskName"].toString();
        task.mode = static_cast<SamplingMode>(taskObj["mode"].toInt());
        task.parameter = taskObj["parameter"].toInt();
        task.scheduled_time = QDateTime::fromString(taskObj["scheduledTime"].toString(), Qt::ISODate);
        task.operator_id = taskObj["operatorId"].toString();
        task.is_recurring = taskObj["isRecurring"].toBool();
        task.recurrence_interval = taskObj["recurrenceInterval"].toInt();
        task.is_active = taskObj["isActive"].toBool();
        
        if (validateTaskParameters(task)) {
            m_tasks.append(task);
            importedCount++;
        }
    }
    
    if (importedCount > 0) {
        saveTasksToDatabase();
        emit pendingTasksChanged(getPendingTasksCount());
        scheduleNextTask();
    }
    
    logTaskOperation(-1, "IMPORT_TASKS", QString("Imported %1 tasks from %2").arg(importedCount).arg(filePath).toLocal8Bit().data());
    qDebug() << "Imported" << importedCount << "tasks from:" << filePath;
    
    return importedCount > 0;
}

// Private slots
void SamplingManager::checkScheduledTasks()
{
    QDateTime now = QDateTime::currentDateTime();
    
    for (auto& task : m_tasks) {
        if (task.is_active && task.scheduled_time <= now && m_currentTaskId == -1) {
            // Execute the task
            if (executeTask(task.task_id)) {
                // If recurring, schedule next occurrence
                if (task.is_recurring) {
                    task.scheduled_time = now.addSecs(task.recurrence_interval * 60);
                    saveTasksToDatabase();
                    emit nextTaskScheduled(task.scheduled_time);
                } else {
                    // Remove non-recurring completed task
                    task.is_active = false;
                }
            }
            break; // Execute only one task at a time
        }
    }
    
    // Update schedule status
    updateScheduleStatus();
    
    // Remove expired tasks periodically
    static int cleanupCounter = 0;
    if (++cleanupCounter >= 360) { // Every hour (360 * 10 seconds)
        removeExpiredTasks();
        cleanupCounter = 0;
    }
}

void SamplingManager::onDeviceSamplingCompleted(const SamplingRecord& record)
{
    if (m_currentTaskId != -1) {
        emit taskCompleted(m_currentTaskId, true);
        
        m_completedTasksCount++;
        emit completedTasksChanged(m_completedTasksCount);
        
        logTaskOperation(m_currentTaskId, "TASK_COMPLETED", 
                        QString("Task completed successfully - Volume: %1L, Time: %2s")
                        .arg(record.actual_volume).arg(record.actual_time).toLocal8Bit().data());
        
        m_currentTaskId = -1;
        updateScheduleStatus();
        scheduleNextTask();
    }
}

void SamplingManager::onDeviceError(const QString& error)
{
    if (m_currentTaskId != -1) {
        emit taskError(m_currentTaskId, error);
        emit taskCompleted(m_currentTaskId, false);
        
        logTaskOperation(m_currentTaskId, "TASK_ERROR", 
                        QString("Task failed with error: %1").arg(error).toLocal8Bit().data());
        
        m_currentTaskId = -1;
        m_scheduleStatus = SCHEDULE_ERROR;
        emit scheduleStatusChanged(m_scheduleStatus);
    }
}

// Private methods
bool SamplingManager::executeTask(int taskId)
{
    SamplingTask* task = findTask(taskId);
    if (!task || !task->is_active) {
        qDebug() << "Cannot execute task:" << taskId;
        return false;
    }
    
    if (!m_deviceController) {
        qDebug() << "Device controller not available";
        return false;
    }
    
    // Check if device is ready
    if (m_deviceController->getDeviceStatus() != DEVICE_IDLE) {
        qDebug() << "Device is not ready for sampling";
        return false;
    }
    
    m_currentTaskId = taskId;
    m_scheduleStatus = SCHEDULE_EXECUTING;
    emit scheduleStatusChanged(m_scheduleStatus);
    emit taskStarted(taskId);
    
    // Start sampling based on task mode
    bool success = m_deviceController->startSampling(task->mode, task->parameter);
    
    if (!success) {
        QString error = m_deviceController->getLastError();
        emit taskError(taskId, error);
        emit taskCompleted(taskId, false);
        
        m_currentTaskId = -1;
        m_scheduleStatus = SCHEDULE_ERROR;
        emit scheduleStatusChanged(m_scheduleStatus);
        
        return false;
    }
    
    logTaskOperation(taskId, "TASK_STARTED", 
                    QString("Task execution started: %1").arg(task->task_name).toLocal8Bit().data());
    
    qDebug() << "Task execution started:" << task->task_name << "ID:" << taskId;
    return true;
}

void SamplingManager::updateScheduleStatus()
{
    if (m_currentTaskId != -1) {
        m_scheduleStatus = SCHEDULE_EXECUTING;
    } else if (getPendingTasksCount() > 0) {
        m_scheduleStatus = SCHEDULE_WAITING;
    } else {
        m_scheduleStatus = SCHEDULE_IDLE;
    }
    
    emit scheduleStatusChanged(m_scheduleStatus);
}

void SamplingManager::logTaskOperation(int taskId, const char* operation, const char* details)
{
    qDebug() << "logTaskOperation: Starting with taskId:" << taskId << "operation:" << operation;
    
    if (m_auditLogger) {
        qDebug() << "logTaskOperation: AuditLogger is available, creating record...";
        AuditLogger::AuditRecord record;
        record.timestamp = QDateTime::currentDateTime();
        record.userId = "system"; // This should be set from user session
        record.action = AuditLogger::System;
        record.tableName = "sampling_tasks";
        record.recordId = QString::number(taskId);
        record.oldValue = "";
        record.newValue = QString(details);
        record.description = QString("Sampling Task Operation: %1 - %2").arg(operation).arg(details);
        
        qDebug() << "logTaskOperation: About to call m_auditLogger->logEvent...";
        m_auditLogger->logEvent(record);
        qDebug() << "logTaskOperation: m_auditLogger->logEvent completed";
    } else {
        qDebug() << "logTaskOperation: AuditLogger is null, skipping audit log";
    }
    
    qDebug() << "Task Operation:" << operation << "-" << details;
    qDebug() << "logTaskOperation: Completed successfully";
}

SamplingTask* SamplingManager::findTask(int taskId)
{
    for (auto& task : m_tasks) {
        if (task.task_id == taskId) {
            return &task;
        }
    }
    return nullptr;
}

void SamplingManager::scheduleNextTask()
{
    QDateTime nextTime = getNextScheduledTime();
    if (nextTime.isValid()) {
        emit nextTaskScheduled(nextTime);
    }
}

bool SamplingManager::validateTaskParameters(const SamplingTask& task)
{
    if (task.task_name.isEmpty()) {
        return false;
    }
    
    if (task.mode == SAMPLING_TIMED) {
        return task.parameter > 0 && task.parameter <= 86400; // Max 24 hours
    } else if (task.mode == SAMPLING_VOLUME) {
        return validateSamplingVolume(task.parameter);
    }
    
    return false;
}

void SamplingManager::removeExpiredTasks()
{
    QDateTime cutoffTime = QDateTime::currentDateTime().addDays(-7); // Remove tasks older than 7 days
    
    for (int i = m_tasks.size() - 1; i >= 0; --i) {
        const SamplingTask& task = m_tasks[i];
        if (!task.is_active && !task.is_recurring && task.scheduled_time < cutoffTime) {
            qDebug() << "Removing expired task:" << task.task_name;
            m_tasks.removeAt(i);
        }
    }
    
    saveTasksToDatabase();
}

bool SamplingManager::saveTasksToDatabase()
{
    // This would save tasks to SQLite database
    // For now, we'll implement a simple JSON file backup
    QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QDir().mkpath(dataDir);
    QString filePath = dataDir + "/sampling_tasks.json";
    
    return exportTasks(filePath);
}

bool SamplingManager::loadTasksFromDatabase()
{
    // This would load tasks from SQLite database
    // For now, we'll load from JSON file backup
    QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = dataDir + "/sampling_tasks.json";
    
    if (QFile::exists(filePath)) {
        return importTasks(filePath);
    }
    
    return true; // No existing tasks is not an error
}

void SamplingManager::createTasksTable()
{
    qDebug() << "Creating sampling tasks table...";
    
    if (!m_auditLogger) {
        qCritical() << "AuditLogger not available for database operations";
        return;
    }
    
    // Get the default database connection
    QSqlDatabase db = QSqlDatabase::database();
    if (!db.isOpen()) {
        qCritical() << "Database connection is not open";
        return;
    }
    
    QSqlQuery query(db);
    
    // Create sampling_tasks table
    QString createTableSQL = R"(
        CREATE TABLE IF NOT EXISTS sampling_tasks (
            task_id INTEGER PRIMARY KEY,
            task_name TEXT NOT NULL,
            mode INTEGER NOT NULL,
            parameter INTEGER NOT NULL,
            scheduled_time DATETIME NOT NULL,
            operator_id TEXT NOT NULL,
            is_recurring INTEGER DEFAULT 0,
            recurrence_interval INTEGER DEFAULT 0,
            is_active INTEGER DEFAULT 1,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    )";
    
    if (!query.exec(createTableSQL)) {
        qCritical() << "Failed to create sampling_tasks table:" << query.lastError().text();
        return;
    }
    
    // Create index for better performance
    QString createIndexSQL = "CREATE INDEX IF NOT EXISTS idx_sampling_tasks_scheduled ON sampling_tasks(scheduled_time)";
    if (!query.exec(createIndexSQL)) {
        qWarning() << "Failed to create index on sampling_tasks:" << query.lastError().text();
    }
    
    qDebug() << "Sampling tasks table created successfully";
}

// C-style helper functions
extern "C" {
    const char* scheduleStatusToString(ScheduleStatus status)
    {
        switch (status) {
            case SCHEDULE_IDLE: return "SCHEDULE_IDLE";
            case SCHEDULE_WAITING: return "SCHEDULE_WAITING";
            case SCHEDULE_EXECUTING: return "SCHEDULE_EXECUTING";
            case SCHEDULE_PAUSED: return "SCHEDULE_PAUSED";
            case SCHEDULE_ERROR: return "SCHEDULE_ERROR";
            default: return "UNKNOWN";
        }
    }
    
    bool isValidTaskId(int taskId)
    {
        return taskId > 0;
    }
    
    int calculateNextRecurrence(int intervalMinutes)
    {
        return intervalMinutes * 60; // Convert to seconds
    }
    
    bool isTaskExpired(const SamplingTask* task)
    {
        if (!task) return true;
        
        QDateTime now = QDateTime::currentDateTime();
        QDateTime cutoff = now.addDays(-7); // 7 days ago
        
        return !task->is_active && !task->is_recurring && task->scheduled_time < cutoff;
    }
}